package cas

import (
	"fmt"
	"sync"

	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	"github.com/casbin/casbin/v2/persist"
)

// CasbinService 封装了 Casbin 的常用操作
type CasbinService struct {
	*casbin.Enforcer
}

var (
	casbinService *CasbinService
	once          sync.Once
)

// InitializeCasbinService 初始化 CasbinService 单实例
func InitializeCasbinService(m model.Model, a persist.Adapter) error {
	var err error
	once.Do(func() {
		casbinService, err = newCasbinService(m, a)
	})
	return err
}

// newCasbinService 创建一个新的 CasbinService 实例
func newCasbinService(m model.Model, a persist.Adapter) (*CasbinService, error) {
	cs := &CasbinService{}
	// 初始化 enforcer
	enforce, err := casbin.NewEnforcer(m, a)
	if err != nil {
		return nil, fmt.Errorf("初始化 enforcer: %w", err)
	}
	cs.Enforcer = enforce
	cs.EnableAutoSave(true)
	cs.LoadPolicy()

	return cs, nil
}

// GetCasbinService 获取单实例的 CasbinService, 必须先调用 InitializeCasbinService 进行初始化
func GetCasbinService() *CasbinService {
	if casbinService == nil {
		panic("CasbinService 未初始化，请先调用 InitializeCasbinService 进行初始化")
	}
	return casbinService
}

// AddPolicy 添加授权规则
func (cs *CasbinService) AddPolicy(role, app, url, action string) (bool, error) {
	b, err := cs.Enforcer.AddPolicy(role, app, url, action)
	if err != nil {
		cs.LoadPolicy()
	}
	return b, err
}

// RemovePolicy 删除授权规则
func (cs *CasbinService) RemovePolicy(role, app, url, action string) (bool, error) {
	b, err := cs.Enforcer.RemovePolicy(role, app, url, action)
	if err != nil {
		cs.LoadPolicy()
	}
	return b, err
}

// UpdatePolicy 更新授权规则
func (cs *CasbinService) UpdatePolicy(role, oldApp, oldURL, oldAction, newApp, newURL, newAction string) (bool, error) {
	b, err := cs.Enforcer.UpdatePolicy([]string{role, oldApp, oldURL, oldAction}, []string{role, newApp, newURL, newAction})
	if err != nil {
		cs.LoadPolicy()
	}
	return b, err
}

// AddUserToRole 添加用户到角色
func (cs *CasbinService) AddUserToRole(user, role string) (bool, error) {
	b, err := cs.AddGroupingPolicy(user, role)
	if err != nil {
		cs.LoadPolicy()
	}
	return b, err
}

// RemoveUserFromRole 删除用户角色关系
func (cs *CasbinService) RemoveUserFromRole(user, role string) (bool, error) {
	b, err := cs.RemoveGroupingPolicy(user, role)
	if err != nil {
		cs.LoadPolicy()
	}
	return b, err
}

// Enforce 检查权限
func (cs *CasbinService) Enforce(user, app, url, action string) (bool, error) {
	return cs.Enforcer.Enforce(user, app, url, action)
}
